From 01fd68a4ee58965ae8e45366010c69688914d6a5 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 5 Jun 2005 14:05:20 +0000 Subject: [PATCH] bitkeeper revision 1.1676 (42a306a07UKpLq27_iCaJyxJBbKedg) More console cleanups. The console ring now overwrites its tail when it fills, rather than stop recording output. The guest serial output is only allowed to half-fill the serial output buffer, and now respects hypercall preemption requests. Signed-off-by: Keir Fraser --- tools/libxc/xc.h | 4 +- tools/libxc/xc_misc.c | 28 ++++----- tools/python/xen/lowlevel/xc/xc.c | 7 ++- xen/common/dom0_ops.c | 8 ++- xen/common/domain.c | 13 +---- xen/drivers/char/console.c | 97 ++++++++++++++++++++----------- xen/drivers/char/serial.c | 8 +++ xen/include/public/dom0_ops.h | 8 ++- xen/include/xen/console.h | 3 +- xen/include/xen/serial.h | 3 + 10 files changed, 107 insertions(+), 72 deletions(-) diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 29e642d4cb..3c768f1a4a 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -388,8 +388,8 @@ int xc_physdev_pci_access_modify(int xc_handle, int enable); int xc_readconsolering(int xc_handle, - char *str, - unsigned int max_chars, + char **pbuffer, + unsigned int *pnr_chars, int clear); typedef dom0_physinfo_t xc_physinfo_t; diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index 9ce8548709..40291bc3ef 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -19,34 +19,35 @@ int xc_interface_close(int xc_handle) return close(xc_handle); } - -#define CONSOLE_RING_CLEAR 1 - int xc_readconsolering(int xc_handle, - char *str, - unsigned int max_chars, + char **pbuffer, + unsigned int *pnr_chars, int clear) { int ret; dom0_op_t op; + char *buffer = *pbuffer; + unsigned int nr_chars = *pnr_chars; op.cmd = DOM0_READCONSOLE; - op.u.readconsole.str = (unsigned long)str; - op.u.readconsole.count = max_chars; - op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0; + op.u.readconsole.buffer = buffer; + op.u.readconsole.count = nr_chars; + op.u.readconsole.clear = clear; - if ( (ret = mlock(str, max_chars)) != 0 ) + if ( (ret = mlock(buffer, nr_chars)) != 0 ) return ret; - if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 ) - str[ret] = '\0'; + if ( (ret = do_dom0_op(xc_handle, &op)) == 0 ) + { + *pbuffer = op.u.readconsole.buffer; + *pnr_chars = op.u.readconsole.count; + } - (void)munlock(str, max_chars); + (void)munlock(buffer, nr_chars); return ret; } - int xc_physinfo(int xc_handle, xc_physinfo_t *put_info) { @@ -64,7 +65,6 @@ int xc_physinfo(int xc_handle, return 0; } - int xc_sched_id(int xc_handle, int *sched_id) { diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 9b35ded02a..013fbe1fcc 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -678,7 +678,8 @@ static PyObject *pyxc_readconsolering(PyObject *self, XcObject *xc = (XcObject *)self; unsigned int clear = 0; - char str[32768]; + char _str[32768], *str = _str; + unsigned int count = 32768; int ret; static char *kwd_list[] = { "clear", NULL }; @@ -686,11 +687,11 @@ static PyObject *pyxc_readconsolering(PyObject *self, if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) ) return NULL; - ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear); + ret = xc_readconsolering(xc->xc_handle, &str, &count, clear); if ( ret < 0 ) return PyErr_SetFromErrno(xc_error); - return PyString_FromStringAndSize(str, ret); + return PyString_FromStringAndSize(str, count); } static PyObject *pyxc_physinfo(PyObject *self, diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 89654c7c45..4221c18c7e 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -449,9 +449,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op) case DOM0_READCONSOLE: { - ret = read_console_ring(op->u.readconsole.str, - op->u.readconsole.count, - op->u.readconsole.cmd); + ret = read_console_ring( + &op->u.readconsole.buffer, + &op->u.readconsole.count, + op->u.readconsole.clear); + copy_to_user(u_dom0_op, op, sizeof(*op)); } break; diff --git a/xen/common/domain.c b/xen/common/domain.c index c832a83410..127c57fe17 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -122,18 +122,9 @@ void domain_kill(struct domain *d) void domain_crash(void) { - struct domain *d = current->domain; - - if ( d->domain_id == 0 ) - { - show_registers(guest_cpu_user_regs()); - panic("Domain 0 crashed!\n"); - } - -#ifndef NDEBUG + printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n", + current->domain->domain_id, current->vcpu_id, smp_processor_id()); show_registers(guest_cpu_user_regs()); -#endif - domain_shutdown(SHUTDOWN_crash); } diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index db80be7983..5ade44b42b 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,13 +43,10 @@ boolean_param("sync_console", opt_sync_console); static int xpos, ypos; static unsigned char *video; -#define CONSOLE_RING_SIZE 16392 -typedef struct console_ring_st -{ - char buf[CONSOLE_RING_SIZE]; - unsigned int len; -} console_ring_t; -static console_ring_t console_ring; +#define CONRING_SIZE 16384 +#define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1)) +static char conring[CONRING_SIZE]; +static unsigned int conringc, conringp; static char printk_prefix[16] = ""; @@ -218,23 +216,33 @@ static void putchar_console(int c) static void putchar_console_ring(int c) { - if ( console_ring.len < CONSOLE_RING_SIZE ) - console_ring.buf[console_ring.len++] = (char)c; + conring[CONRING_IDX_MASK(conringp++)] = c; + if ( (conringp - conringc) > CONRING_SIZE ) + conringc = conringp - CONRING_SIZE; } -long read_console_ring(unsigned long str, unsigned int count, unsigned cmd) +long read_console_ring(char **pstr, u32 *pcount, int clear) { - unsigned int len; - - len = (console_ring.len < count) ? console_ring.len : count; - - if ( copy_to_user((char *)str, console_ring.buf, len) ) - return -EFAULT; + char *str = *pstr; + u32 count = *pcount; + unsigned int p, q; + unsigned long flags; - if ( cmd & CONSOLE_RING_CLEAR ) - console_ring.len = 0; - - return len; + /* Start of buffer may get overwritten during copy. So copy backwards. */ + for ( p = conringp, q = count; (p > conringc) && (q > 0); p--, q-- ) + if ( put_user(conring[CONRING_IDX_MASK(p-1)], (char *)str+q-1) ) + return -EFAULT; + + if ( clear ) + { + spin_lock_irqsave(&console_lock, flags); + conringc = conringp; + spin_unlock_irqrestore(&console_lock, flags); + } + + *pstr = str + q; + *pcount = count - q; + return 0; } @@ -301,13 +309,44 @@ static void serial_rx(char c, struct cpu_user_regs *regs) __serial_rx(c, regs); } +long guest_console_write(char *buffer, int count) +{ + char kbuf[128]; + int kcount; + + while ( count > 0 ) + { + while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) ) + { + if ( hypercall_preempt_check() ) + break; + cpu_relax(); + } + + if ( hypercall_preempt_check() ) + return hypercall3_create_continuation( + __HYPERVISOR_console_io, CONSOLEIO_write, count, buffer); + + kcount = min_t(int, count, sizeof(kbuf)-1); + if ( copy_from_user(kbuf, buffer, kcount) ) + return -EFAULT; + kbuf[kcount] = '\0'; + + serial_puts(sercon_handle, kbuf); + + buffer += kcount; + count -= kcount; + } + + return 0; +} + long do_console_io(int cmd, int count, char *buffer) { - char *kbuf; - long rc; + long rc; #ifndef VERBOSE - /* Only domain-0 may access the emergency console. */ + /* Only domain 0 may access the emergency console. */ if ( current->domain->domain_id != 0 ) return -EPERM; #endif @@ -315,17 +354,7 @@ long do_console_io(int cmd, int count, char *buffer) switch ( cmd ) { case CONSOLEIO_write: - if ( count > (PAGE_SIZE-1) ) - count = PAGE_SIZE-1; - if ( (kbuf = (char *)alloc_xenheap_page()) == NULL ) - return -ENOMEM; - kbuf[count] = '\0'; - rc = count; - if ( copy_from_user(kbuf, buffer, count) ) - rc = -EFAULT; - else - serial_puts(sercon_handle, kbuf); - free_xenheap_page((unsigned long)kbuf); + rc = guest_console_write(buffer, count); break; case CONSOLEIO_read: rc = 0; diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 51cfaa56eb..a59146da0a 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -317,6 +317,14 @@ void serial_end_sync(int handle) spin_unlock_irqrestore(&port->lock, flags); } +int serial_tx_space(int handle) +{ + struct serial_port *port = &com[handle & SERHND_IDX]; + if ( handle == -1 ) + return SERIAL_TXBUFSZ; + return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc); +} + void serial_init_preirq(void) { int i; diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 4c3d5271a2..0768b8c6ae 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -164,9 +164,11 @@ typedef struct { */ #define DOM0_READCONSOLE 19 typedef struct { - memory_t str; - u32 count; - u32 cmd; + /* IN variables. */ + u32 clear; /* Non-zero -> clear after reading. */ + /* IN/OUT variables. */ + char *buffer; /* In: Buffer start; Out: Used buffer start */ + u32 count; /* In: Buffer size; Out: Used buffer size */ } dom0_readconsole_t; /* diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h index 4295a41de6..12028cdc97 100644 --- a/xen/include/xen/console.h +++ b/xen/include/xen/console.h @@ -13,8 +13,7 @@ extern spinlock_t console_lock; void set_printk_prefix(const char *prefix); -#define CONSOLE_RING_CLEAR 1 -long read_console_ring(unsigned long, unsigned int, unsigned int); +long read_console_ring(char **, u32 *, int); void init_console(void); void console_endboot(int disable_vga); diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 9a1dd60cf4..8d5f246ab2 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -96,6 +96,9 @@ void serial_force_unlock(int handle); void serial_start_sync(int handle); void serial_end_sync(int handle); +/* Return number of bytes headroom in transmit buffer. */ +int serial_tx_space(int handle); + /* * Initialisation and helper functions for uart drivers. */ -- 2.30.2